# -*- coding: utf-8 -*-

__author__ = """WebLion <support@weblion.psu.edu>"""
__docformat__ = 'plaintext'

from AccessControl import ClassSecurityInfo
from Products.Archetypes.atapi import *
from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget
from Products.CMFCore.permissions import View
from Products.ContactsDirectory.PersonGrouping import PersonGrouping
from Products.Relations.field import RelationField
from Products.ContactsDirectory.config import *
from zope.interface import implements
from Products.CMFCore.utils import getToolByName
from Products.membrane.interfaces import IPropertiesProvider
from Products.ContactsDirectory.interfaces.organization import IOrganization
from Acquisition import aq_inner, aq_parent
from Products.ContactsDirectory.permissions import ASSIGN_COMMITTIES_TO_PEOPLE

from Products.ContactsDirectory.validators import SequenceValidator
from Products.validation import validation
from Products.CMFCore.permissions import View, ModifyPortalContent, SetOwnPassword, SetOwnProperties

from Products.ATVocabularyManager import NamedVocabulary

import re
from sha import sha

schema = Schema((
    
    StringField(
        name='organizationType',
        widget=SelectionWidget(
            label=u"Provider Status",
            label_msgid='ContactsDirectory_label_providerStatus',
            i18n_domain='ContactsDirectory',
        ),
        vocabulary=NamedVocabulary("""organizationType"""),
        schemata="Professional Information"
    ),
    
    StringField(
        name='email',
        user_property=True,
        widget=StringWidget(
            label=u'Email',
            label_msgid='ContactsDirectory_label_email',
            i18n_domain='ContactsDirectory',
        ),
        schemata="Contact Information",
        searchable=True,
        validators=('isEmail',)
    ),
    
    StringField(
        name='officeAddress',
        widget=TextAreaWidget(
            label=u"Office Street Address",
            label_msgid='ContactsDirectory_label_officeAddress',
            i18n_domain='ContactsDirectory',
        ),
        schemata="Contact Information",
        searchable=True
    ),
    
    StringField(
        name='officeCity',
        widget=StringWidget(
            label=u"Office City",
            label_msgid='ContactsDirectory_label_officeCity',
            i18n_domain='ContactsDirectory',
        ),
        schemata="Contact Information",
        searchable=True
    ),
    
    StringField(
        name='officeProvince',
        widget=SelectionWidget(
            label=u"Office Province",
            label_msgid='ContactsDirectory_label_officeProvince',
            i18n_domain='ContactsDirectory',
        ),    
        vocabulary=NamedVocabulary("""provinces"""),
        schemata="Contact Information"
    ),
        
    StringField(
        name='officePostalCode',
        widget=StringWidget(
            label=u"Office Postal Code",
            label_msgid='ContactsDirectory_label_officePostalCode',
            i18n_domain='ContactsDirectory',
        ),
        schemata="Contact Information"
    ),
    
    StringField(
        name='officePhone',
        widget=StringWidget(
            label=u"Office Phone",
            description="",
            label_msgid='ContactsDirectory_label_officePhone',
            description_msgid='ContactsDirectory_description_officePhone',
            i18n_domain='ContactsDirectory',
        ),
        schemata="Contact Information",
        searchable=True,
    ),
    
    ImageField(
        name='image',
        schemata="Basic Information",
        widget=ImageWidget(
            label=u'Image',
            label_msgid='ContactsDirectory_label_image',
            i18n_domain='ContactsDirectory',
            default_content_type='image/gif',
        ),
        storage=AttributeStorage(),
        original_size=(400, 500),
        sizes={'thumb': (100, 125), 'normal': (200, 250)},
        default_output_type='image/jpeg',
        allowable_content_types=('image/gif','image/jpeg','image/png'),
    ),
    
    LinesField(
        name='websites',
        widget=LinesField._properties['widget'](
            label=u"Web Sites",
            description="One per line. Example: http://www.example.com/",
            label_msgid='ContactsDirectory_label_websites',
            description_msgid='ContactsDirectory_description_websites',
            i18n_domain='ContactsDirectory',
        ),
        schemata="Basic Information",
        validators = SequenceValidator('isURLs', validation.validatorFor('isURL'))
    ),
    
#     RelationField(
#         name='contacts',
#         widget=ReferenceBrowserWidget
#         (
#             label=u"Organization's Contact(s)",
#             label_msgid='ContactsDirectory_label_contacts',
#             i18n_domain='ContactsDirectory',
#             base_query={'portal_type': 'CDPerson', 'sort_on': 'sortable_title'},
#             allow_browse=0,
#             allow_search=1,
#             show_results_without_query=1,
#         ),
#         write_permission="Modify portal content",
#         schemata="Basic Information",
#         multiValued=True,
# #        relationship='people_assistants',
#         relationship='organization_contacts',
#         allowed_types=('CDPerson'),
#     ),

    RelationField(
        name='members',
        widget=ReferenceBrowserWidget(
            label=u'Members',
            label_msgid='ContactsDirectory_label_members',
            i18n_domain='ContactsDirectory',
            base_query={'portal_type':'CDPerson', 'sort_on':'getSortableName'},
            allow_browse=0,
            allow_search=1,
            show_results_without_query=1,
        ),
        write_permission = ASSIGN_COMMITTIES_TO_PEOPLE,
        allowed_types=('CDPerson',),
        multiValued=True,
        relationship='OrganizationMembership'
    ),
),
)

Organization_schema = getattr(PersonGrouping, 'schema', Schema(())).copy() + schema.copy()

class Organization(PersonGrouping):
    """
    """
    security = ClassSecurityInfo()
    __implements__ = (getattr(PersonGrouping,'__implements__',()),)
    # zope3 interfaces
    implements(IOrganization, IPropertiesProvider)
    meta_type = portal_type = 'CDOrganization'
    _at_rename_after_creation = True
    schema = Organization_schema
    # Methods
    if 'categorization' in Organization_schema.getSchemataNames():
        Organization_schema.changeSchemataForField('description', 'settings')
    else:
        Organization_schema.changeSchemataForField('description', 'metadata')
        Organization_schema.changeSchemataForField('relatedItems', 'metadata')
        
    #
    security.declareProtected(View, 'vcard_view')
    def vcard_view(self, REQUEST, RESPONSE):
        """vCard 3.0 output
        """
        RESPONSE.setHeader('Content-Type', 'text/x-vcard')
        RESPONSE.setHeader('Content-Disposition', 'attachment; filename="%s.vcf"' % self.getId())
        out = StringIO()
        
        # Get the fields using the accessors, so they're properly Unicode encoded.
        out.write("BEGIN:VCARD\nVERSION:3.0\n")
        out.write("FN:%s\n" % self.Title())
        #out.write("N:%s;%s\n" % (self.getLastName(), self.getFirstName()))
        #out.write(foldLine("TITLE:%s\n" % '\\n'.join(self.getJobTitles())))
        out.write(foldLine("ADR;TYPE=dom,postal,parcel,work:;;%s;%s;%s;%s\n" % (self.getOfficeAddress().replace('\r\n','\\n'), self.getOfficeCity(), self.getOfficeProvince(), self.getOfficePostalCode())))
        out.write("TEL;WORK:%s\n" % self.getOfficePhone())
        out.write("EMAIL;TYPE=internet:%s\n" % self.getEmail())
        
        #Add the Person page to the list of URLs
        urls = list(self.getWebsites())
        urls.append(self.absolute_url())
        for url in urls:
            out.write(foldLine("URL:%s\n" % url))
        if self.getImage():
            encData = self.image_thumb.data.encode('base-64')
            # indent the data block:
            indentedData = '\n  '.join(encData.strip().split('\n'))
            out.write("PHOTO;ENCODING=BASE64;TYPE=JPEG:\n  %s\n" % indentedData)
        out.write("REV:%s\n" % DateTime(self.ModificationDate()).ISO8601())
        out.write("PRODID:NSIF Contacts Directory\nEND:VCARD")
        return n2rn(out.getvalue())
        
    #
    security.declareProtected(View, 'getSortableName')
    def getSortableName(self):
        """
        Return a tuple of the person's name. For sorting purposes
        Return them as lowercase so that names like 'von Whatever' sort properly
        """
        return (self.Title().lower(), '')
        
    #
    security.declareProtected(View, 'getProvinceNames')
    def getProvinceNames(self):
        """ Returns a list of the titles of the provinces attached to this person.
            Mainly used for pretty-looking metadata in SmartFolder tables. Returns an
            alphabetically-sorted list since Provinces can be located anywhere within the site,
            which makes using any other sort order somewhat problematic.
        """
        dList = [d.Title() for d in self.getProvinces()]
        dList.sort()
        return dList
    
    #
    security.declareProtected(View, 'tag')
    def tag(self, **kwargs):
        """Pass along the 'tag' method to the Person's image."""
        return self.getWrappedField('image').tag(self, **kwargs)
        
    #
    security.declareProtected(View, 'getImageOfSize')
    def getImageOfSize(self, height, width, **kwargs):
        """Return the person's image sized to the given dimensions."""
        return self.getWrappedField('image').tag(self, width=width, height=height, **kwargs)
        
    #
    security.declareProtected(View, 'getScaledImageByWidth')
    def getScaledImageByWidth(self, preferredWidth, **kwargs):
        """Return the person's image sized to the given width and a height scaled according to the original image ratio. Fail nicely, returning no image tag. This seems to occur when TIFF images are used."""
        if not (self.image.height or self.image.width):
            logger.error("There was an error resizing the image for person %s" % self)
            return ''
        hwratio = float(self.image.height)/float(self.image.width)
        calcHeight = int(preferredWidth * hwratio)
        return self.getImageOfSize(calcHeight, preferredWidth, **kwargs)
    
    security.declareProtected(ModifyPortalContent, 'setImage')
    def setImage(self, value, **kwargs):
        field = self.getField('image')
        
        # If the image exists in portal memberdata's portraits folder, delete it
        md = getToolByName(self, 'portal_memberdata')
        if md.portraits.has_key(self.id):
            md.portraits._delObject(self.id)
        
        # Assign the image to the field
        field.set(self, value)
        
        # If there is an image value (not the empty string that seems to get sent on object creation)
        # and it's not a delete command, create a member portrait
        if value and value != 'DELETE_IMAGE':
            # Add the new portrait
            md.portraits._setObject(id=self.id, object=self.getImage())
            
    #
    security.declarePrivate('validate_officePhone')
    def validate_officePhone(self, value=None):
        """ Make sure the phone number fits the regex defined in the configuration. """
        if value:
            cd_tool = getToolByName(self, TOOLNAME)
            regexString = cd_tool.getPhoneNumberRegex()
            if regexString and not re.match(regexString, value):
                return "Please provide the phone number in the format %s" % cd_tool.getPhoneNumberDescription()
    
    security.declareProtected(View, 'getMembershipInformation')
    def getMembershipInformation(self, person):
        """ Get the organization membership information for a specific person
        """
        refCatalog = getToolByName(self, 'reference_catalog')
        refs = refCatalog.getReferences(self, 'OrganizationMembership', person)

        if not refs:
            return None
        else:
            return refs[0].getContentObject()

    security.declareProtected(View, 'getPeople')
    def getPeople(self):
        """ Return the people in this organization.
            Mainly for context-sensitive classifications
        """
        return self.getMembers()

    security.declareProtected(View, 'getRawPeople')
    def getRawPeople(self):
        """ Return the people associations associated with this organization
        """
        return self.getRawMembers()

    #
    # Validators
    #
    security.declarePrivate('validate_id')
    def validate_id(self, value):
        """Ensure the id is unique, also among groups globally
        """
        if value != self.getId():
            parent = aq_parent(aq_inner(self))
            if value in parent.objectIds():
                return "An object with id '%s' already exists in this folder" % value
        
            groups = getToolByName(self, 'portal_groups')
            if groups.getGroupById(value) is not None:
                return "A group with id '%s' already exists in the portal" % value

registerType(Organization, PROJECTNAME)
# end of class Organization

